/**
 * @file mqtt_client.c
 * @author your name (you@domain.com)
 * @brief 简单的 MQTT客户端应用程序示例
 * @version 0.1
 * @date 2023-07-07
 * 
 * @copyright Copyright (c) 2023
 * 
 */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include "MQTTClient.h"

#define BROKER_ADDRESS "tcp://iot.ranye-iot.net:1883"
#define CLIENTID    "user" /* 客户端id */
#define USERNAME    "u22user" /* 用户名 */
#define PASSWORD    "password" /* 密码 */
#define WILL_TOPIC  "topic" /* 遗嘱主题 */
#define LED_TOPIC   "topic" /* LED主题 */
#define TEMP_TOPIC  "topic" /* 温度主题 */

/**
 * @brief 
 * 
 * @param context 
 * @param topicName 
 * @param topicLen 
 * @param message 
 * @return int 
 */
static int msgarrvd(void *context, char *topicName, int topicLen, 
                    MQTTClient_message *message)
{
    if (!strcmp(topicName, LED_TOPIC)) { /* 校验消息的主题 */
        if (!strcmp("2", message->payload)) { /* 如果接收到的消息是“2”则设置LED为呼吸灯模式 */
            system("echo heartbeat > /sys/class/leds/sys-led/trigger");
        }
        if (!strcmp("1", message->payload)) { /* 如果是“1”则设置LED常亮 */
            system("echo none > /sys/class/leds/sys-led/trigger");
            system("echo 1 > /sys/class/leds/sys-led/brightness");
        } else if (!strcmp("0", message->payload)) { /* 如果是“0”则设置LED常灭 */
            system("echo none > /sys/class/leds/sys-led/trigger");
            system("echo 0 > /sys/class/leds/sys-led/brightness");
        }
        /* 接收到其他数据，不做处理 */
    }
    /* 释放占用的内存空间 */
    MQTTClient_freeMessage(&message);
    MQTTClient_free(topicName);

    return 1;
}

/**
 * @brief 
 * 
 * @param context 
 * @param cause 
 */
static void connlost(void *context, char *cause)
{
    printf("\nConnection lost\n");
    printf("    cause: %s\n", cause);
}

int main(int argc, char const *argv[])
{
    MQTTClient client;
    MQTTClient_connectOptions conn_opts = MQTTClient_connectOptions_initializer;
    MQTTClient_willOptions will_opts = MQTTClient_willOptions_initializer;
    MQTTClient_message pubmsg = MQTTClient_message_initializer;
    int rc;

    /* 创建 mqtt客户端对象 */
    if (MQTTCLIENT_SUCCESS != 
            (rc = MQTTClient_create(&client, BROKER_ADDRESS, CLIENTID,
                    MQTTCLIENT_PERSISTENCE_NONE, NULL))) {
        printf("MQTTClient_create failed, error code %d\n", rc);
        rc = EXIT_FAILURE;
        goto exit;
    }
    /* 设置回调函数 */
    if (MQTTCLIENT_SUCCESS !=
            (rc = MQTTClient_setCallbacks(client, NULL, connlost, msgarrvd,
                    NULL))) {
        printf("MQTTClient_setCallbacks failed, error code %d\n", rc);
        rc = EXIT_FAILURE;
        goto destroy_exit;
    }
    /* 连接 MQTT服务器 */
    will_opts.topicName = WILL_TOPIC; /* 遗嘱主题 */
    will_opts.message = "Unexpected disconnection"; /* 遗嘱内容 */
    will_opts.retained = 1; /* 保留 */
    will_opts.qos = 0; /* QoS等级 0 */

    conn_opts.will = &will_opts;
    conn_opts.keepAliveInterval = 30; /* 心跳间隔 30s */
    conn_opts.username = USERNAME; /* 登陆用户名 */
    conn_opts.password = PASSWORD; /* 登陆密码 */
    if (MQTTCLIENT_SUCCESS != 
            (rc = MQTTClient_connect(client, &conn_opts))) {
        printf("Failed to connect, return code %d\n", rc);
        rc = EXIT_FAILURE;
        goto destroy_exit;
    }
    printf("MQTT 服务器连接成功！\n");

    /* 发布上线消息 */
    pubmsg.payload = "Online"; /* 消息的内容 */
    pubmsg.payloadlen = sizeof("Online"); /* 消息的长度 */
    pubmsg.qos = 0; /* QoS等级 */
    pubmsg.retained = 1; /* 保留消息 */
    if (MQTTCLIENT_SUCCESS != 
          (rc = MQTTClient_publishMessage(client, WILL_TOPIC, &pubmsg, NULL))) {
        printf("Failed to publish message, return code %d\n", rc);
        rc = EXIT_FAILURE;
        goto disconnect_exit;
    }
    /* 订阅主题 led */
    if (MQTTCLIENT_SUCCESS != 
          (rc = MQTTClient_subscribe(client, LED_TOPIC, 0))) { 
        printf("Failed to subscribe, return code %d\n", rc);
        rc = EXIT_FAILURE;
        goto disconnect_exit;
    }
    /* 向服务端发布芯片温度信息 */
    for (;;) {
        MQTTClient_message tempmsg = MQTTClient_message_initializer;
        char temp_str[10] = {0};
        int fd;

        /* 读取温度值 */
        fd = open("sys/class/thermal/thermal_zone0/temp", O_RDONLY);
        read(fd, temp_str, sizeof(temp_str)); /* 获取温度 */
        close(fd);
        /* 发布温度信息 */
        tempmsg.payload = temp_str; /* 消息的内容 */
        tempmsg.payloadlen = strlen(temp_str); /* 内容的长度 */
        tempmsg.qos = 0; /* QoS等级 */
        tempmsg.retained = 1; /* 保留消息 */
        if (MQTTCLIENT_SUCCESS != 
              (rc = MQTTClient_publishMessage(client, TEMP_TOPIC, &tempmsg, 
                        NULL))) {
            printf("Failed to publish message, return code %d\n", rc);
            rc = EXIT_FAILURE;
            goto unsubscribe_exit;
        }
        sleep(30); /* 每隔30s更新一次数据 */
    }

unsubscribe_exit:
    if (MQTTCLIENT_SUCCESS != 
          (rc = MQTTClient_unsubscribe(client, LED_TOPIC))) {
        printf("Failed to unsubscribe, return code %d\n", rc);
        rc = EXIT_FAILURE;
    }
disconnect_exit:
    if (MQTTCLIENT_SUCCESS != 
          (rc = MQTTClient_disconnect(client, 10000))) {
        printf("Failed to disconnect, return code %d\n", rc);
        rc = EXIT_FAILURE;
    }
destroy_exit:
    MQTTClient_destroy(&client);
exit:
    return rc;
}
